/**
 * 
 * @author Tommy MacWilliam
 * @version 0.3
 * Last revised 10/14/08
 *
 */
package tmacsoftware.Filio;

import java.io.*;

public class Filio {

    private File _ioFile;

    /** 
     * Constructor, creates file if not already existing
     * @param ioFile File to read/write to
     */
    public Filio(File ioFile) {
        if (!ioFile.exists()) {
            try {
                ioFile.createNewFile();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
        _ioFile = ioFile;
    }

    /**
     * Constructor, creates file if not already existing
     * @param path Path to file
     */
    public Filio(String path) {
        File ioFile = new File(path);
        if (!ioFile.exists()) {
            try {
                ioFile.createNewFile();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
        _ioFile = ioFile;
    }

    /**
     * Convert string array to single string
     * Each element of the array represents a line
     * @param array String array to concatenate
     * @return String representation of array
     */
    private String arrayToString(String[] array) {
        // Create StringBuilder to concatenate array
        StringBuilder stringData = new StringBuilder();
        // Convert array back to single string
        for (int i = 0; i < array.length; i++) {
            stringData.append(array[i]);
            // Preserve newlines from original file
            stringData.append(System.getProperty("line.separator"));
        }
        return stringData.toString();
    }

    /**
     * Get total number of lines in file
     * @return Integer representing number of lines in file (starting at 1)
     */
    public int getTotalLines() {
        int currLine = 0;
        try {
            // Point reader to file being manipulated
            BufferedReader input = new BufferedReader(new FileReader(_ioFile));
            try {
                String line = null;
                // Count number of lines in file
                while ((line = input.readLine()) != null) {
                    currLine++;
                }
            } finally {
                // Close file stream
                input.close();
            }
        } catch (FileNotFoundException ex) {
            ex.printStackTrace();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        return currLine;
    }

    /**
     * Get total number of characters in file
     * @return Integer representing number of characters in file
     */
    public int getTotalCharacters() {
        String data = read();
        return data.length();
    }

    /**
     * Read all data in file
     * @return String containing file data
     */
    public String read() {
        // Create string to hold all file data
        StringBuilder contents = new StringBuilder();
        try {
            // Point reader to file being manipulated
            BufferedReader input = new BufferedReader(new FileReader(_ioFile));
            try {
                String line = null;
                // Append all lines to content string
                while ((line = input.readLine()) != null) {
                    contents.append(line);
                    contents.append(System.getProperty("line.separator"));
                }
            } finally {
                // Close file stream
                input.close();
                // Delete trailing newline
                contents.replace(contents.length() - 1, contents.length(), "");
            }
        } catch (FileNotFoundException ex) {
            ex.printStackTrace();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        return contents.toString();
    }

    /**
     * Read one line from file
     * @param lineToRead Line to read
     * @return String containing contents of line
     */
    public String read(int lineToRead) {
        // Create string to hold line data
        StringBuilder contents = new StringBuilder();
        try {
            // Point reader to file being manipulated
            BufferedReader input = new BufferedReader(new FileReader(_ioFile));
            try {
                String line = null;
                int currLine = 0;
                // Read all lines of file
                while ((line = input.readLine()) != null) {
                    if (currLine == lineToRead) {
                        // Only save string data for matching line
                        contents.append(line);
                    }
                    currLine++;
                }
            } finally {
                // Close file stream
                input.close();
            }
        } catch (FileNotFoundException ex) {
            ex.printStackTrace();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        return contents.toString();
    }

    /**
     * Read multiple lines from file
     * @param startLine Line to startLine reading from
     * @param endLine Line to stop reading from
     * @return String containing data from lines
     */
    public String read(int startLine, int endLine) {
        // Create string to hold file data
        StringBuilder contents = new StringBuilder();
        try {
            // Point reader to file being manipulated
            BufferedReader input = new BufferedReader(new FileReader(_ioFile));
            try {
                String line = null;
                int currLine = 0;
                // Read all lines of file
                while ((line = input.readLine()) != null) {
                    // Only save data between given endpoints
                    if (currLine >= startLine && currLine <= endLine) {
                        contents.append(line);
                        contents.append(System.getProperty("line.separator"));
                    }
                    currLine++;
                }
            } finally {
                // Close file stream
                input.close();
                // Delete trailing newline
                contents.replace(contents.length() - 1, contents.length(), "");
            }
        } catch (FileNotFoundException ex) {
            ex.printStackTrace();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        return contents.toString();
    }

    /** 
     * Overwrite entire file with new data
     * @param data Data to be written to file
     */
    public void write(String data) {
        try {
            // Point writer to file being manipulated
            Writer output = new BufferedWriter(new FileWriter(_ioFile));
            // Write new file to disk
            output.write(data);
            // Close file stream
            output.close();
        } catch (FileNotFoundException ex) {
            ex.printStackTrace();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

    /**
     * Overwrite line with new data
     * @param data Data to be written to file
     * @param line Line to overwrite
     */
    public void write(String data, int line) {
        // Store all file data in string
        String fileData = read();
        // Split file into array
        String[] fileLines = fileData.split(System.getProperty("line.separator"));
        // Replace line with new data
        fileLines[line] = data;
        // Convert array to single string and write to file
        write(arrayToString(fileLines));
    }

    /**
     * Append data to end of file
     * @param data Data to append to file
     */
    public void append(String data) {
        // Read current file
        String fileData = read();
        // Add data to string
        fileData += data;
        // Write file to disk
        write(fileData);
    }

    /**
     * Append data to end of line
     * @param data Data to append to file
     * @param line Line to append data to
     */
    public void append(String data, int line) {
        // Read current file
        String fileData = read();
        // Split file into array
        String[] fileLines = fileData.split(System.getProperty("line.separator"));
        // Add data to end of line
        fileLines[line] += data;
        // Convert to single string and save to disk
        write(arrayToString(fileLines));
    }

    /**
     * Insert data at a point
     * @param startLine Position to startLine inserting
     * @param data Data to insert
     */
    public void insert(String data, int start) {
        // Save file data in string
        StringBuilder fileData = new StringBuilder();
        fileData.append(read());
        // Insert data at given starting point
        fileData.insert(start, data);
        // Save file to disk
        write(fileData.toString());
    }

    /**
     * Insert data to a position in a line 
     * @param lineStart Line number to startLine writing at
     * @param charStart Character number to startLine writing at
     * @param data Data to write
     */
    public void insert(String data, int lineStart, int charStart) {
        // Store all file data in string
        String fileData = read();
        // Split file into array
        String[] fileLines = fileData.split(System.getProperty("line.separator"));
        // Store file data in string
        StringBuilder lineData = new StringBuilder();
        lineData.append(read(lineStart));
        // Insert new data into lines
        lineData.insert(charStart, data);
        // Replace old line with new line containing data
        fileLines[lineStart] = lineData.toString();
        // Convert to array and save to disk
        write(arrayToString(fileLines));
    }

    public void delete(int line) {
        // Store all file data in string
        String fileData = read();
        // Split file into array
        String[] fileLines = fileData.split(System.getProperty("line.separator"));
        // Replace line with empty string
        fileLines[line] = "";
        // Convert to single string and write file to disk
        write(arrayToString(fileLines));
    }

    /**
     * Delete characters between start and end position
     * @param start Position to start deleting characters
     * @param end Position to stop deleting characters
     */
    public void delete(int start, int end) {
        StringBuilder fileData = new StringBuilder();
        // Read entire file
        fileData.append(read());
        // Overwrite characters in given interval with blank string
        fileData.replace(start, end, "");
        // Save file
        write(fileData.toString());
    }

    /**
     * Delete characters on a certain line between startLine and endLine position
     * @param line Line in which to delete characters
     * @param start Position on line to start deleting characters
     * @param end Position on line to stop deleting characters
     */
    public void delete(int line, int start, int end) {
        // Character in end argument should be deleted
        end++;
        // Read entire file
        String fileData = read();
        // Split file into array
        String[] fileLines = fileData.split(System.getProperty("line.separator"));
        StringBuilder deleteLine = new StringBuilder();
        // Add line to delete characters from to array
        deleteLine.append(fileLines[line]);
        deleteLine.replace(start, end, "");
        // Replace line with new string
        fileLines[line] = deleteLine.toString();
        // Convert to string and save to disk
        write(arrayToString(fileLines));
    }
}